package services

import (
	"fmt"
	"time"

	"github.com/EDDYCJY/go-gin-example/models"
	"github.com/EDDYCJY/go-gin-example/pkg/openai/aijieyun/pkg/services/avpc"

	"github.com/jinzhu/gorm"
)

// // 定义RentOrder模型
// type RentOrder struct {
// 	ID                uint64   `gorm:"primary_key"`
// 	UserID            uint64   `gorm:"column:user_id"`
// 	SubmitMachineRecordID uint64 `gorm:"column:submit_machine_record_id"`
// 	RentType          uint32   `gorm:"rent_type"`
// 	TaskID            string   `gorm:"column:task_id"`
// 	RentStartTime     DbTime   `gorm:"column:rent_start_time"`
// 	RentEndTime       DbTime   `gorm:"column:rent_end_time"`
// 	UpdateTime        DbTime   `gorm:"column:update_time"`
// }

// 定义订购流程的结构体
type OrderProcess struct {
	*gorm.DB
	// *aecs.Client
	// *requests.RpcRequest
	Work Worker
	// *responses.BaseResponse
}

type Worker interface {
	DoWork() error
	GetID() string
}

// NewOrderProcess 创建一个新的订购流程实例
func NewOrderProcess(db *gorm.DB, work Worker) *OrderProcess {
	return &OrderProcess{DB: db, Work: work}
}

// DeductFee 扣除用户积分逻辑
// 如果扣费失败，返回相应的错误
func (op *OrderProcess) DeductFee(userID uint64, amount float64, tx *gorm.DB) error {

	if tx == nil {
		return fmt.Errorf("事务未开启: %v", tx.Error)
	}
	// 获取用户账户信息（在同一个事务中执行）
	account, err := models.GetAccountByUserIdWithDb(userID, tx)
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("获取用户积分信息失败: %v", err)
	}

	// 检查用户积分是否足够支付
	if account.Coins < amount {
		return fmt.Errorf("用户积分不足，无法支付")
	}

	// 扣除用户积分
	newCoins := account.Coins - amount
	updateData := map[string]interface{}{
		"coins": newCoins,
	}
	err = tx.Model(&models.Account{}).Where("id = ?", userID).Updates(updateData).Error
	if err != nil {
		return fmt.Errorf("扣除用户积分失败: %v", err)
	}
	return nil
}

// CreateRentOrder 创建租用订单
func (op *OrderProcess) CreateRentOrder(order *models.RentOrder, tx *gorm.DB) error {
	// 在提供的事务内创建租用订单
	err := tx.Create(order).Error
	if err != nil {
		return fmt.Errorf("创建租用订单失败: %v", err)
	}

	return nil
}

// 订购流程的创建机器步骤
func (op *OrderProcess) CreateMachine() error {
	err := op.Work.DoWork()
	if err != nil {
		return fmt.Errorf("创建机器失败: %w", err)
	}
	return nil
}

// AllocateAndAssociateEipAddress是整个流程的入口函数
// 给机器分配网络并绑定IP
func (op *OrderProcess) AllocateAndAssociateEipAddress() error {
	eipAllocator := NewEIPAllocator(&avpc.DefaultClient, op.Work)
	go eipAllocator.AllocateAndAssociateEipAddress()
	return nil

}

// 订购流程的更新租用结束时间步骤
func (op *OrderProcess) UpdateRentEndTime(orderID uint64, endTime time.Time) error {
	// 在这里实现更新租用结束时间的逻辑，如果更新失败，返回相应的错误
	// return op.DB.Model(&RentOrder{}).Where("id = ?", orderID).Update("rent_end_time", endTime).Error
	return nil
}

type OrderRequest struct {
	UserID          uint64
	Amount          float64
	Configuration   string
	LeaseTimeSecond int64
	AutoRenew       bool
}

// 订购流程的整体执行方法
func (op *OrderProcess) PerformOrder(req *OrderRequest) error {
	// 开始数据库事务
	tx := op.DB.Begin()
	if tx.Error != nil {
		return fmt.Errorf("无法开始事务: %v", tx.Error)
	}
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	// 1. 根据费用信息进行扣费
	if err := op.DeductFee(req.UserID, req.Amount, tx); err != nil {
		// 处理扣费失败情况
		tx.Rollback()
		return fmt.Errorf("扣费失败: %v", err)
	}

	// 2. 创建机器（通过调用远程API）
	err := op.CreateMachine()
	if err != nil {
		// 处理创建机器失败情况
		tx.Rollback()
		return err
	}
	now := time.Now()
	// 创建租用订单
	order := models.RentOrder{
		UserId:        req.UserID,
		RentType:      models.RentTypeAjiyun,
		RentStartTime: models.DbTime(now),
		RentEndTime:   models.DbTime(calculateExpirationDate(now, req.LeaseTimeSecond)), //计算租用结束时间
		UpdateTime:    models.DbTime(now),
		AutoRenew:     req.AutoRenew,
		TaskId:        op.Work.GetID(),
	}
	// 3. 创建租用订单
	err = op.CreateRentOrder(&order, tx)
	if err != nil {
		tx.Rollback()
		return err
	}

	// 4. 创建支付记录
	paymentRecord := models.PaymentRecord{}
	paymentRecord.UserId = req.UserID
	paymentRecord.RentPeriod = uint64(req.LeaseTimeSecond)
	paymentRecord.PaymentCoins = req.Amount
	paymentRecord.PaymentTime = models.DbTime(now)
	paymentRecord.PaymentType = models.PaymentTypeRentAiJiYun
	// if req.AutoRenew {
	// 	paymentRecord.PaymentType = models.PaymentTypeRentAiJiYun_renew
	// }
	err = tx.Debug().Create(&paymentRecord).Error
	if err != nil {
		tx.Rollback()
		return fmt.Errorf("无法创建支付记录: %v", err)
	}

	// 提交数据库事务
	if err := tx.Commit().Error; err != nil {
		return fmt.Errorf("无法提交事务: %v", err)
	}

	//给机器默认分配网络
	_ = op.AllocateAndAssociateEipAddress()

	return nil

}

// 计算租用结束时间的函数（单位：秒）
func calculateExpirationDate(now time.Time, rentDuration int64) time.Time {
	return now.Add(time.Duration(rentDuration) * time.Second)
}

// 订购流程的续费步骤
// func (op *OrderProcess) RenewOrder(orderID uint64, renewalAmount float64) error {
// 	// 在这里实现续费逻辑，包括验证续费条件、计算新的租用结束时间等
// 	// 假设续费成功并更新订单信息
// 	newEndTime := calculateNewExpirationDate()
// 	if err := op.UpdateRentEndTime(orderID, newEndTime); err != nil {
// 		return fmt.Errorf("更新租用结束时间失败: %v", err)
// 	}

// 	// 记录续费信息
// 	renewalRecord := RenewalRecord{
// 		OrderID:     orderID,
// 		RenewalTime: DbTime{Time: time.Now()},
// 		Amount:      renewalAmount,
// 	}
// 	if err := op.DB.Create(&renewalRecord).Error; err != nil {
// 		return fmt.Errorf("记录续费信息失败: %v", err)
// 	}

// 	return nil
// }

// func main() {
// 	// 连接数据库
// 	db, err := gorm.Open("sqlite3", "test.db")
// 	if err != nil {
// 		panic("无法连接到数据库")
// 	}
// 	defer db.Close()

// 	// 自动迁移数据库表
// 	db.AutoMigrate(&Price{}, &RentOrder{}, &RenewalRecord{})

// 	// 创建订购流程实例
// 	orderProcess := NewOrderProcess(db)

// 	// 模拟数据
// 	userID := uint(1)
// 	amount := 100.0
// 	configuration := "Machine Configuration"

// 	// 开始订购流程
// 	if err := orderProcess.PerformOrder(userID, amount, configuration); err != nil {
// 		fmt.Println("订购流程失败:", err)
// 		return
// 	}

// 	fmt.Println("订购流程成功")

// 	// 模拟续费操作
// 	renewalAmount := 50.0
// 	orderID := uint64(1)

// 	if err := orderProcess.RenewOrder(orderID, renewalAmount); err != nil {
// 		fmt.Println("续费失败:", err)
// 		return
// 	}

// 	fmt.Println("续费成功")
// }
